/**
 * Copyright 2008 - 2009 Pro-Netics S.P.A.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package it.pronetics.madstore.hatom.alfresco.util;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

import nu.xom.Attribute;
import nu.xom.Comment;
import nu.xom.Element;
import nu.xom.Node;
import nu.xom.ParentNode;

/**
 * A class of useful methods made to manage Select Items for this plug-in.
 * 
 * @author Salvatore Incandela
 */

public class SelectItemUtils {

	public static final String NOT_SELECTED = "Not selected.";

	/**
	 * This method retrieve the first Comment Node above the element passed. In
	 * the runtime searching phase, if another Element Node with the same name
	 * it's found before a comment, this method return an empty String.
	 * 
	 * @param element
	 *            nu.xom.Element
	 * @return The (String) value of the Comment Node
	 */

	public static String retrieveComment(Element element) {
		String result = "";
		ParentNode parent = element.getParent();
		int indexElement = parent.indexOf(element);
		Attribute classAttribute = element.getAttribute("class");
		if (indexElement == 0
				&& (classAttribute == null || !classAttribute
						.equals(HAtomDialogUtils.HATOM_HENTRY))) {
			return retrieveComment((Element) parent);
		}
		for (int i = indexElement - 1; i >= 0; i--) {
			Node node = parent.getChild(i);
			if (node instanceof Element) {
				Element previousElement = (Element) node;
				if (isElementContaingElementOfName(previousElement,
						"xsl:value-of")) {
					return result;
				}
			}
			if (node instanceof Comment) {
				Comment comment = (Comment) node;
				return " : " + comment.getValue();
			}
		}
		return result;
	}

	/**
	 * This method checks if there is an Element with the passed QualifiedName
	 * between the children of the passed Element. Also, it checks if the passed
	 * Element has the same qualifiedName of the passedOne.
	 * 
	 * @param element
	 * @param qualifiedName
	 * @return true if the passed Element, or one of its subElements, has the
	 *         same qualifiedName of the passed one, false otherwise.
	 */

	private static boolean isElementContaingElementOfName(Element element,
			String qualifiedName) {
		boolean result = false;
		if (element.getQualifiedName().equals(qualifiedName)) {
			return true;
		}
		for (int i = 0; i < element.getChildCount(); i++) {
			Node child = element.getChild(i);
			if (child instanceof Element) {
				Element elementChild = (Element) child;
				return isElementContaingElementOfName(elementChild,
						qualifiedName);
			}
		}
		return result;
	}

	/**
	 * This method makes a human readable label used in the JSF selects for
	 * Element of type <xsl:value-of select="..." />.
	 * 
	 * @param element
	 *            nu.xom.Element
	 * @return (String) Label for the passed element.
	 */

	public static String makeLabel(Element element) {
		String property = element.getAttributeValue("select");
		property = formatProperty(property);
		if (property.equals(".")) {
			property = retrievePropertyNameFromXslForEach(element);
		}
		return capitalize(property);
	}

	/**
	 * This method formats the value of the 'select' attribute of an Element
	 * Node of type <xsl:value-of select="..." />.
	 * 
	 * @param property
	 *            (String) value of 'select' attribute
	 * @return formatted String
	 */

	private static String formatProperty(String property) {
		int first = property.indexOf(")");
		int last = property.lastIndexOf("(") + 1;
		if (first == -1) {
			first = property.length();
		}
		String[] propertyArray = (property.substring(last, first)).split(":");
		property = propertyArray[propertyArray.length - 1];
		return property;
	}

	/**
	 * This method retrieves the name of the current property in a JSF for-each.
	 * The passed Element Node has to have the expression '.' in its attributes.
	 * 
	 * @param element
	 *            passed Element Node.
	 * @return (String) Name of the current property.
	 */

	private static String retrievePropertyNameFromXslForEach(Element element) {
		List<Node> parents = new ArrayList<Node>();
		XomUtils.getParents(element, parents);
		String result = "";
		for (Node parent : parents) {
			if (parent instanceof Element) {
				Element elementParent = (Element) parent;
				if (elementParent.getQualifiedName().equals("xsl:for-each")) {
					return formatProperty(elementParent
							.getAttributeValue("select"))
							+ " in iteration";
				}
			}
		}
		return result;
	}

	/**
	 * Capitalize a String.
	 * 
	 * @param s
	 *            String to capitalize.
	 * @return Capitalized String.
	 */

	public static String capitalize(String s) {
		char chars[] = s.toCharArray();
		chars[0] = Character.toUpperCase(chars[0]);
		return new String(chars);
	}

	public static SelectItem getSelectItem(Element element, String rootAddress) {
		String comment = retrieveComment(element);
		String label = makeLabel(element);
		String nameSelect = label + " " + comment;
		String address = rootAddress + getAddress(element);
		String valueSelect = "Address: " + address + " -- " + nameSelect;
		SelectItem item = new SelectItem(valueSelect, nameSelect);
		return item;
	}

	public static String getValueSelect(Element elementChild, String rootAddress) {
		Element property = elementChild.getChildElements().get(0);
		String comment = retrieveComment(elementChild);
		String label = makeLabel(property);
		String nameSelect = label + " " + comment;
		String address = rootAddress + getAddress(elementChild);
		String valueSelect = "Address: " + address + " -- " + nameSelect;
		return valueSelect;
	}

	public static SelectItem getSelectItem(Element element) {
		String comment = retrieveComment(element);
		String label = makeLabel(element);
		String nameSelect = label + " " + comment;
		String address = getAddress(element);
		String valueSelect = "Address: " + address + " -- " + nameSelect;
		SelectItem item = new SelectItem(valueSelect, nameSelect);
		return item;
	}

	public static String getValueSelect(Element elementChild) {
		Element property = elementChild.getChildElements().get(0);
		String comment = retrieveComment(elementChild);
		String label = makeLabel(property);
		String nameSelect = label + " " + comment;
		String address = getAddress(elementChild);
		String valueSelect = "Address: " + address + " -- " + nameSelect;
		return valueSelect;
	}

	public static String getAddress(Node node) {
		return computeAddress(node, "");
	}

	private static String computeAddress(Node node, String address) {
		ParentNode parent = node.getParent();
		if (parent == null) {
			return address;
		} else {
			int index = parent.indexOf(node);
			address = index + address;
			return computeAddress(parent, address);
		}
	}

}
